/*
 * Copyright (c) 2023 iQi.Co.Ltd. All rights reserved.
 */
 
using System.Collections.Generic;
using NetProtocol.POD;
using NetProtocol.Enum;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using IQIGame.Onigao.Framework;
using Cysharp.Threading.Tasks;
using System;
using static IQIGame.Onigao.Game.MessageWrapper;

namespace NetProtocol.Client {
	/// <summary>
	/// 逻辑服连接模块
	/// module : logicServer
	/// </summary>
	public interface CNetLogicServer : INetClientModule {
		
		public ISession GetSession();
	
		Dictionary<int, INetClientModule.Package2MessageWrapper> INetClientModule.GetModuleFunction()
        {
            MessageFunction connectResult_Delegate = (session, wrapper) =>
            {
            	var _wrapper = (MessageWrapper<ConnectResultData>)wrapper;
                SC_connectResult(session, ref _wrapper.message);
                MessageWrapperPool<ConnectResultData>.Put(_wrapper);
            };
            MessageFunction reconnectResult_Delegate = (session, wrapper) =>
            {
            	var _wrapper = (MessageWrapper<ReconnectResultData>)wrapper;
                SC_reconnectResult(session, ref _wrapper.message);
                MessageWrapperPool<ReconnectResultData>.Put(_wrapper);
            };
            MessageFunction pang_Delegate = (session, wrapper) =>
            {
            var _wrapper = (MessageWrapper<PangData>)wrapper; 
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_pang, "Recv->" + _wrapper.message.ToString());
#endif
                SC_pang(session, _wrapper.message.serverTime);
                MessageWrapperPool<PangData>.Put(_wrapper);
            };
            MessageFunction logoutResult_Delegate = (session, wrapper) =>
            {
            	var _wrapper = (MessageWrapper<LogoutResultData>)wrapper;
                SC_logoutResult(session, ref _wrapper.message);
                MessageWrapperPool<LogoutResultData>.Put(_wrapper);
            };
            MessageFunction notifyServerStatus_Delegate = (session, wrapper) =>
            {
            var _wrapper = (MessageWrapper<NotifyServerStatusData>)wrapper; 
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_notifyServerStatus, "Recv->" + _wrapper.message.ToString());
#endif
                SC_notifyServerStatus(session, _wrapper.message.time, _wrapper.message.rawOffset, _wrapper.message.testMode);
                MessageWrapperPool<NotifyServerStatusData>.Put(_wrapper);
            };
            MessageFunction notifyError_Delegate = (session, wrapper) =>
            {
            var _wrapper = (MessageWrapper<NotifyErrorData>)wrapper; 
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_notifyError, "Recv->" + _wrapper.message.ToString());
#endif
                SC_notifyError(session, _wrapper.message.code, _wrapper.message.msg);
                MessageWrapperPool<NotifyErrorData>.Put(_wrapper);
            };
            MessageFunction notifyOffline_Delegate = (session, wrapper) =>
            {
            var _wrapper = (MessageWrapper<NotifyOfflineData>)wrapper; 
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_notifyOffline, "Recv->" + _wrapper.message.ToString());
#endif
                SC_notifyOffline(session);
                MessageWrapperPool<NotifyOfflineData>.Put(_wrapper);
            };
        
            Dictionary<int, INetClientModule.Package2MessageWrapper> retDic = new()
            {
                {NetMessageId.logicServer_connectResult, (session, package) => {
                	var result = MessageWrapperPool<ConnectResultData>.Get();
                	result.Init(session, connectResult_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
                {NetMessageId.logicServer_reconnectResult, (session, package) => {
                	var result = MessageWrapperPool<ReconnectResultData>.Get();
                	result.Init(session, reconnectResult_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
                {NetMessageId.logicServer_pang, (session, package) => {
                	var result = MessageWrapperPool<PangData>.Get();
                	result.Init(session, pang_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
                {NetMessageId.logicServer_logoutResult, (session, package) => {
                	var result = MessageWrapperPool<LogoutResultData>.Get();
                	result.Init(session, logoutResult_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
                {NetMessageId.logicServer_notifyServerStatus, (session, package) => {
                	var result = MessageWrapperPool<NotifyServerStatusData>.Get();
                	result.Init(session, notifyServerStatus_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
                {NetMessageId.logicServer_notifyError, (session, package) => {
                	var result = MessageWrapperPool<NotifyErrorData>.Get();
                	result.Init(session, notifyError_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
                {NetMessageId.logicServer_notifyOffline, (session, package) => {
                	var result = MessageWrapperPool<NotifyOfflineData>.Get();
                	result.Init(session, notifyOffline_Delegate);
                	result.FromPackage(package);
                	return result;
                }},
            };
            return retDic;
        }
#region Client-side Interface
		/// <summary>
        /// connectId=连接id,用于断线重连
        /// </summary>
		public void SC_connectResult(ISession session, ref ConnectResultData message) 
		{
            _SC_connectResult(session, ref message);
		}
		
		public void _SC_connectResult(ISession session, ref ConnectResultData message)
		{
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_connectResult, "Recv->" + message.ToString());
#endif
			NetProtocolHelper.endCallRequest?.Invoke(NetMessageId.logicServer_connectResult, message.code);
			MsgAsyncAwaiter<ConnectResultData>.Instance.CompleteMsgAwait(ref message);
		}
		
		/// <summary>
        /// 
        /// </summary>
		public void SC_reconnectResult(ISession session, ref ReconnectResultData message) 
		{
            _SC_reconnectResult(session, ref message);
		}
		
		public void _SC_reconnectResult(ISession session, ref ReconnectResultData message)
		{
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_reconnectResult, "Recv->" + message.ToString());
#endif
			NetProtocolHelper.endCallRequest?.Invoke(NetMessageId.logicServer_reconnectResult, message.code);
			MsgAsyncAwaiter<ReconnectResultData>.Instance.CompleteMsgAwait(ref message);
		}
		
		/// <summary>
        /// 心跳回执
        /// </summary>
		protected void SC_pang(ISession session, long serverTime);
		/// <summary>
        /// 登出
        /// </summary>
		public void SC_logoutResult(ISession session, ref LogoutResultData message) 
		{
            _SC_logoutResult(session, ref message);
		}
		
		public void _SC_logoutResult(ISession session, ref LogoutResultData message)
		{
#if ENABLE_NET_LOG || UNITY_EDITOR
            NetProtocolHelper.ClientLog(NetMessageId.logicServer_logoutResult, "Recv->" + message.ToString());
#endif
			NetProtocolHelper.endCallRequest?.Invoke(NetMessageId.logicServer_logoutResult, message.code);
			MsgAsyncAwaiter<LogoutResultData>.Instance.CompleteMsgAwait(ref message);
		}
		
		/// <summary>
        /// 通知系统状态
        /// </summary>
		protected void SC_notifyServerStatus(ISession session, long time, int rawOffset, bool testMode);
		/// <summary>
        /// 通用错误通知,包括被其他人登陆通知
        /// </summary>
		protected void SC_notifyError(ISession session, int code, string msg);
		/// <summary>
        /// 通知下线, 客户端不要进行重连
        /// </summary>
		protected void SC_notifyOffline(ISession session);
#endregion
#region Server-side Interface
		/// <summary>
        /// 连接服务器
        /// </summary>
    	public UniTask<ConnectResultData> CS_connect(string token, string logicServerId, string gameServerId)
        {
            return _CS_connect(token, logicServerId, gameServerId);
        }
        
        public UniTask<ConnectResultData> _CS_connect(string token, string logicServerId, string gameServerId)
        {
        	ISession session = GetSession();
        	if(session == null) return UniTask.FromResult(default(ConnectResultData));
#if ENABLE_NET_LOG || UNITY_EDITOR
			NetProtocolHelper.ClientLog(NetMessageId.logicServer_connect, "Send->"+"LogicServer.CS_connect { "
				+ "token="
				+ token
				+ ", logicServerId="
				+ logicServerId
				+ ", gameServerId="
				+ gameServerId
				+" }");
#endif
        	UniTask<ConnectResultData> task = MsgAsyncAwaiter<ConnectResultData>.Instance.AddMsgAwait();
        	session.SendPack(Pack_for_connect(token, logicServerId, gameServerId));
        	NetProtocolHelper.beginCallRequest?.Invoke(NetMessageId.logicServer_connectResult);
			return task;
        }
		
		public static SendPackage Pack_for_connect(string token, string logicServerId, string gameServerId) 
		{
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_connect;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_string(token);
			_out.Write_string(logicServerId);
			_out.Write_string(gameServerId);
			return si_p;
		}
		/// <summary>
        /// 重连服务器
        /// </summary>
    	public UniTask<ReconnectResultData> CS_reconnect(string reconnectToken, int readMsgCount, string connectId)
        {
            return _CS_reconnect(reconnectToken, readMsgCount, connectId);
        }
        
        public UniTask<ReconnectResultData> _CS_reconnect(string reconnectToken, int readMsgCount, string connectId)
        {
        	ISession session = GetSession();
        	if(session == null) return UniTask.FromResult(default(ReconnectResultData));
#if ENABLE_NET_LOG || UNITY_EDITOR
			NetProtocolHelper.ClientLog(NetMessageId.logicServer_reconnect, "Send->"+"LogicServer.CS_reconnect { "
				+ "reconnectToken="
				+ reconnectToken
				+ ", readMsgCount="
				+ readMsgCount
				+ ", connectId="
				+ connectId
				+" }");
#endif
        	UniTask<ReconnectResultData> task = MsgAsyncAwaiter<ReconnectResultData>.Instance.AddMsgAwait();
        	session.SendPack(Pack_for_reconnect(reconnectToken, readMsgCount, connectId));
        	NetProtocolHelper.beginCallRequest?.Invoke(NetMessageId.logicServer_reconnectResult);
			return task;
        }
		
		public static SendPackage Pack_for_reconnect(string reconnectToken, int readMsgCount, string connectId) 
		{
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_reconnect;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_string(reconnectToken);
			_out.Write_int(readMsgCount);
			_out.Write_string(connectId);
			return si_p;
		}
		/// <summary>
        /// 心跳
        /// </summary>
    	public bool CS_ping() 
    	{
    		return _CS_ping();
    	}
    	public bool _CS_ping()
        {
        	ISession session = GetSession();
        	if(session == null) return false;
#if ENABLE_NET_LOG || UNITY_EDITOR
			NetProtocolHelper.ClientLog(NetMessageId.logicServer_ping, "Send->"+"LogicServer.CS_ping { "
				+" }");
#endif
        	return session.SendPack(Pack_for_ping());
        }
		
		public static SendPackage Pack_for_ping() 
		{
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_ping;
			si_p.StartWrite();
			return si_p;
		}
		/// <summary>
        /// 登出
        /// </summary>
    	public UniTask<LogoutResultData> CS_logout()
        {
            return _CS_logout();
        }
        
        public UniTask<LogoutResultData> _CS_logout()
        {
        	ISession session = GetSession();
        	if(session == null) return UniTask.FromResult(default(LogoutResultData));
#if ENABLE_NET_LOG || UNITY_EDITOR
			NetProtocolHelper.ClientLog(NetMessageId.logicServer_logout, "Send->"+"LogicServer.CS_logout { "
				+" }");
#endif
        	UniTask<LogoutResultData> task = MsgAsyncAwaiter<LogoutResultData>.Instance.AddMsgAwait();
        	session.SendPack(Pack_for_logout());
        	NetProtocolHelper.beginCallRequest?.Invoke(NetMessageId.logicServer_logoutResult);
			return task;
        }
		
		public static SendPackage Pack_for_logout() 
		{
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_logout;
			si_p.StartWrite();
			return si_p;
		}
#endregion
#region Messages
        public struct ConnectResultData : IReceiveMessage {
        	private int? _code;
        	public int code {get{return _code == null ? -1 : (int)_code;}private set{_code = value;}}
	        public string reconnectToken;
	        public string connectId;
            public bool IsFail => _code != null && _code != 0;
            public bool IsSuccess =>_code != null && _code == 0;
            public bool IsCanceled => _code == null;
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
                code = _in.HasRemaining() ? _in.Read_int() : default;
                reconnectToken = _in.HasRemaining() ? _in.Read_string() : default;
                connectId = _in.HasRemaining() ? _in.Read_string() : default;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_connectResult;}
            
            public override string ToString()
            {
                return "LogicServer.connectResult"+ ", code="+ code+ ", reconnectToken="+ reconnectToken+ ", connectId="+ connectId;
            }
        }
        public struct ReconnectResultData : IReceiveMessage {
        	private int? _code;
        	public int code {get{return _code == null ? -1 : (int)_code;}private set{_code = value;}}
	        public int lastMsgOrder;
	        public string reconnectToken;
	        public string connectId;
            public bool IsFail => _code != null && _code != 0;
            public bool IsSuccess =>_code != null && _code == 0;
            public bool IsCanceled => _code == null;
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
                code = _in.HasRemaining() ? _in.Read_int() : default;
                lastMsgOrder = _in.HasRemaining() ? _in.Read_int() : default;
                reconnectToken = _in.HasRemaining() ? _in.Read_string() : default;
                connectId = _in.HasRemaining() ? _in.Read_string() : default;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_reconnectResult;}
            
            public override string ToString()
            {
                return "LogicServer.reconnectResult"+ ", code="+ code+ ", lastMsgOrder="+ lastMsgOrder+ ", reconnectToken="+ reconnectToken+ ", connectId="+ connectId;
            }
        }
        public struct PangData : IReceiveMessage {
	        public long serverTime;
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
                serverTime = _in.HasRemaining() ? _in.Read_long() : default;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_pang;}
            
            public override string ToString()
            {
                return "LogicServer.pang"+ ", serverTime="+ serverTime;
            }
        }
        public struct LogoutResultData : IReceiveMessage {
        	private int? _code;
        	public int code {get{return _code == null ? -1 : (int)_code;}private set{_code = value;}}
            public bool IsFail => _code != null && _code != 0;
            public bool IsSuccess =>_code != null && _code == 0;
            public bool IsCanceled => _code == null;
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
                code = _in.HasRemaining() ? _in.Read_int() : default;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_logoutResult;}
            
            public override string ToString()
            {
                return "LogicServer.logoutResult"+ ", code="+ code;
            }
        }
        public struct NotifyServerStatusData : IReceiveMessage {
	        public long time;
	        public int rawOffset;
	        public bool testMode;
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
                time = _in.HasRemaining() ? _in.Read_long() : default;
                rawOffset = _in.HasRemaining() ? _in.Read_int() : default;
                testMode = _in.HasRemaining() ? _in.Read_boolean() : default;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_notifyServerStatus;}
            
            public override string ToString()
            {
                return "LogicServer.notifyServerStatus"+ ", time="+ time+ ", rawOffset="+ rawOffset+ ", testMode="+ testMode;
            }
        }
        public struct NotifyErrorData : IReceiveMessage {
	        public int code;
	        public string msg;
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
                code = _in.HasRemaining() ? _in.Read_int() : default;
                msg = _in.HasRemaining() ? _in.Read_string() : default;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_notifyError;}
            
            public override string ToString()
            {
                return "LogicServer.notifyError"+ ", code="+ code+ ", msg="+ msg;
            }
        }
        public struct NotifyOfflineData : IReceiveMessage {
            public void FromPackage(ReceivePackage _package)
            {
                SInputStream _in = _package.InputStream;
            }
            
            public int GetMessageId() {return NetMessageId.logicServer_notifyOffline;}
            
            public override string ToString()
            {
                return "LogicServer.notifyOffline";
            }
        }
    }
#endregion
}